{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import backtrader as bt\n",
    "import akshare as ak\n",
    "from datetime import datetime\n",
    "import PySimpleGUI as sg\n",
    "# from backtrader_plotting import Bokeh\n",
    "# from backtrader_plotting.schemes import Tradimo\n",
    "\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']  #显示中文\n",
    "plt.rcParams['axes.unicode_minus']=False #用来正常显示负号\n",
    "\n",
    "%matplotlib inline\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "沪深300行情数据\n",
      "               open     high      low    close    volume  openinterest\n",
      "date                                                                  \n",
      "2010-04-06  3422.85  3436.29  3386.89  3405.15  65191710             0\n",
      "2010-04-07  3403.09  3404.58  3369.02  3386.95  54011228             0\n",
      "2010-04-08  3381.31  3381.31  3336.16  3346.74  62185322             0\n",
      "2010-04-09  3348.77  3379.40  3342.47  3379.17  51280567             0\n",
      "2010-04-12  3388.35  3393.56  3330.30  3351.48  74565150             0\n",
      "--------------------------------------------------------------------------------\n"
     ]
    }
   ],
   "source": [
    "#Step1.数据加载\n",
    "\n",
    "#获取user输入\n",
    "stock_code = 600600\n",
    "\n",
    "\n",
    "\n",
    "start_date = datetime(2010, 4, 3)\n",
    "end_date = datetime(2024, 5, 22)\n",
    "\n",
    "#获取沪深300数据作为基准\n",
    "hs300 = ak.index_zh_a_hist(symbol = '000300',period='daily',start_date=start_date,end_date=end_date)\n",
    "hs300 = hs300.iloc[:, :6]\n",
    "hs300.columns = ['date','open','close','high','low','volume']\n",
    "hs300.index = pd.to_datetime(hs300.date)\n",
    "hs300['openinterest'] = 0\n",
    "columns_to_keep = ['open','high','low','close','volume','openinterest']    # 转换为backtrader要求的数据格式\n",
    "hs300 = hs300[columns_to_keep].copy()\n",
    "print('沪深300行情数据')\n",
    "print(hs300.head())\n",
    "print(f'{\"-\" * 80}')\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "#获取股票数据\n",
    "df = ak.stock_zh_a_hist(symbol=\"000001\", period=\"daily\", \n",
    "                                        start_date=\"20200101\", end_date='20200315', adjust=\"qfq\").iloc[:, :6]\n",
    "# 处理字段命名\n",
    "df.columns = ['date', 'open', 'close', 'high', 'low', 'volume',]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>open</th>\n",
       "      <th>close</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>volume</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2020-01-02</td>\n",
       "      <td>15.74</td>\n",
       "      <td>15.96</td>\n",
       "      <td>16.04</td>\n",
       "      <td>15.64</td>\n",
       "      <td>1530232</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2020-01-03</td>\n",
       "      <td>16.03</td>\n",
       "      <td>16.27</td>\n",
       "      <td>16.40</td>\n",
       "      <td>16.01</td>\n",
       "      <td>1116195</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2020-01-06</td>\n",
       "      <td>16.10</td>\n",
       "      <td>16.16</td>\n",
       "      <td>16.43</td>\n",
       "      <td>16.00</td>\n",
       "      <td>862084</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2020-01-07</td>\n",
       "      <td>16.22</td>\n",
       "      <td>16.24</td>\n",
       "      <td>16.37</td>\n",
       "      <td>16.04</td>\n",
       "      <td>728608</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2020-01-08</td>\n",
       "      <td>16.09</td>\n",
       "      <td>15.75</td>\n",
       "      <td>16.14</td>\n",
       "      <td>15.72</td>\n",
       "      <td>847824</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2020-01-09</td>\n",
       "      <td>15.90</td>\n",
       "      <td>15.88</td>\n",
       "      <td>16.02</td>\n",
       "      <td>15.62</td>\n",
       "      <td>1031637</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>2020-01-10</td>\n",
       "      <td>15.88</td>\n",
       "      <td>15.78</td>\n",
       "      <td>15.90</td>\n",
       "      <td>15.61</td>\n",
       "      <td>585548</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>2020-01-13</td>\n",
       "      <td>15.84</td>\n",
       "      <td>16.08</td>\n",
       "      <td>16.12</td>\n",
       "      <td>15.70</td>\n",
       "      <td>872133</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>2020-01-14</td>\n",
       "      <td>16.08</td>\n",
       "      <td>15.85</td>\n",
       "      <td>16.36</td>\n",
       "      <td>15.85</td>\n",
       "      <td>1304494</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>2020-01-15</td>\n",
       "      <td>15.88</td>\n",
       "      <td>15.61</td>\n",
       "      <td>15.95</td>\n",
       "      <td>15.54</td>\n",
       "      <td>859439</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>2020-01-16</td>\n",
       "      <td>15.61</td>\n",
       "      <td>15.42</td>\n",
       "      <td>15.66</td>\n",
       "      <td>15.29</td>\n",
       "      <td>1028105</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>2020-01-17</td>\n",
       "      <td>15.47</td>\n",
       "      <td>15.48</td>\n",
       "      <td>15.64</td>\n",
       "      <td>15.44</td>\n",
       "      <td>605437</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>2020-01-20</td>\n",
       "      <td>15.52</td>\n",
       "      <td>15.54</td>\n",
       "      <td>15.70</td>\n",
       "      <td>15.44</td>\n",
       "      <td>746075</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>2020-01-21</td>\n",
       "      <td>15.43</td>\n",
       "      <td>15.09</td>\n",
       "      <td>15.43</td>\n",
       "      <td>15.02</td>\n",
       "      <td>896603</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>2020-01-22</td>\n",
       "      <td>15.01</td>\n",
       "      <td>15.18</td>\n",
       "      <td>15.25</td>\n",
       "      <td>14.80</td>\n",
       "      <td>719465</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>2020-01-23</td>\n",
       "      <td>15.01</td>\n",
       "      <td>14.63</td>\n",
       "      <td>15.01</td>\n",
       "      <td>14.48</td>\n",
       "      <td>1100592</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>2020-02-03</td>\n",
       "      <td>13.08</td>\n",
       "      <td>13.08</td>\n",
       "      <td>13.79</td>\n",
       "      <td>13.08</td>\n",
       "      <td>2259195</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>2020-02-04</td>\n",
       "      <td>13.14</td>\n",
       "      <td>13.69</td>\n",
       "      <td>13.75</td>\n",
       "      <td>13.11</td>\n",
       "      <td>1706172</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>2020-02-05</td>\n",
       "      <td>13.68</td>\n",
       "      <td>13.72</td>\n",
       "      <td>13.98</td>\n",
       "      <td>13.41</td>\n",
       "      <td>1491380</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>2020-02-06</td>\n",
       "      <td>13.90</td>\n",
       "      <td>13.86</td>\n",
       "      <td>13.96</td>\n",
       "      <td>13.60</td>\n",
       "      <td>1185816</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>2020-02-07</td>\n",
       "      <td>13.69</td>\n",
       "      <td>13.71</td>\n",
       "      <td>13.78</td>\n",
       "      <td>13.50</td>\n",
       "      <td>924853</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>2020-02-10</td>\n",
       "      <td>13.60</td>\n",
       "      <td>13.59</td>\n",
       "      <td>13.62</td>\n",
       "      <td>13.39</td>\n",
       "      <td>1339495</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>2020-02-11</td>\n",
       "      <td>13.69</td>\n",
       "      <td>13.88</td>\n",
       "      <td>14.03</td>\n",
       "      <td>13.65</td>\n",
       "      <td>1407507</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>2020-02-12</td>\n",
       "      <td>13.88</td>\n",
       "      <td>13.86</td>\n",
       "      <td>13.91</td>\n",
       "      <td>13.69</td>\n",
       "      <td>1070503</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>2020-02-13</td>\n",
       "      <td>13.80</td>\n",
       "      <td>13.74</td>\n",
       "      <td>13.97</td>\n",
       "      <td>13.70</td>\n",
       "      <td>1013205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>2020-02-14</td>\n",
       "      <td>13.84</td>\n",
       "      <td>14.12</td>\n",
       "      <td>14.23</td>\n",
       "      <td>13.79</td>\n",
       "      <td>1512435</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>2020-02-17</td>\n",
       "      <td>14.13</td>\n",
       "      <td>14.46</td>\n",
       "      <td>14.46</td>\n",
       "      <td>14.02</td>\n",
       "      <td>1543696</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>2020-02-18</td>\n",
       "      <td>14.42</td>\n",
       "      <td>14.29</td>\n",
       "      <td>14.42</td>\n",
       "      <td>14.10</td>\n",
       "      <td>973612</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>2020-02-19</td>\n",
       "      <td>14.19</td>\n",
       "      <td>14.33</td>\n",
       "      <td>14.46</td>\n",
       "      <td>14.17</td>\n",
       "      <td>874107</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>2020-02-20</td>\n",
       "      <td>14.36</td>\n",
       "      <td>14.68</td>\n",
       "      <td>14.71</td>\n",
       "      <td>14.19</td>\n",
       "      <td>1235444</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>30</th>\n",
       "      <td>2020-02-21</td>\n",
       "      <td>14.58</td>\n",
       "      <td>14.67</td>\n",
       "      <td>14.81</td>\n",
       "      <td>14.54</td>\n",
       "      <td>995071</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31</th>\n",
       "      <td>2020-02-24</td>\n",
       "      <td>14.55</td>\n",
       "      <td>14.32</td>\n",
       "      <td>14.55</td>\n",
       "      <td>14.24</td>\n",
       "      <td>1191795</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32</th>\n",
       "      <td>2020-02-25</td>\n",
       "      <td>14.09</td>\n",
       "      <td>14.13</td>\n",
       "      <td>14.22</td>\n",
       "      <td>13.87</td>\n",
       "      <td>1144575</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>33</th>\n",
       "      <td>2020-02-26</td>\n",
       "      <td>13.86</td>\n",
       "      <td>14.08</td>\n",
       "      <td>14.36</td>\n",
       "      <td>13.79</td>\n",
       "      <td>1176599</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>34</th>\n",
       "      <td>2020-02-27</td>\n",
       "      <td>14.05</td>\n",
       "      <td>14.20</td>\n",
       "      <td>14.24</td>\n",
       "      <td>13.98</td>\n",
       "      <td>975271</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>35</th>\n",
       "      <td>2020-02-28</td>\n",
       "      <td>13.94</td>\n",
       "      <td>13.59</td>\n",
       "      <td>14.13</td>\n",
       "      <td>13.55</td>\n",
       "      <td>1300644</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>36</th>\n",
       "      <td>2020-03-02</td>\n",
       "      <td>13.64</td>\n",
       "      <td>13.88</td>\n",
       "      <td>14.04</td>\n",
       "      <td>13.55</td>\n",
       "      <td>1116581</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>2020-03-03</td>\n",
       "      <td>14.05</td>\n",
       "      <td>13.81</td>\n",
       "      <td>14.08</td>\n",
       "      <td>13.72</td>\n",
       "      <td>1153584</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>2020-03-04</td>\n",
       "      <td>13.77</td>\n",
       "      <td>13.78</td>\n",
       "      <td>13.87</td>\n",
       "      <td>13.60</td>\n",
       "      <td>862595</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>39</th>\n",
       "      <td>2020-03-05</td>\n",
       "      <td>13.89</td>\n",
       "      <td>14.48</td>\n",
       "      <td>14.73</td>\n",
       "      <td>13.82</td>\n",
       "      <td>2686602</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>40</th>\n",
       "      <td>2020-03-06</td>\n",
       "      <td>14.27</td>\n",
       "      <td>14.12</td>\n",
       "      <td>14.36</td>\n",
       "      <td>14.11</td>\n",
       "      <td>1228531</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>41</th>\n",
       "      <td>2020-03-09</td>\n",
       "      <td>13.80</td>\n",
       "      <td>13.54</td>\n",
       "      <td>13.82</td>\n",
       "      <td>13.51</td>\n",
       "      <td>1665794</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>42</th>\n",
       "      <td>2020-03-10</td>\n",
       "      <td>13.47</td>\n",
       "      <td>13.85</td>\n",
       "      <td>13.94</td>\n",
       "      <td>13.47</td>\n",
       "      <td>1167865</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43</th>\n",
       "      <td>2020-03-11</td>\n",
       "      <td>13.86</td>\n",
       "      <td>13.78</td>\n",
       "      <td>13.97</td>\n",
       "      <td>13.71</td>\n",
       "      <td>814382</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>44</th>\n",
       "      <td>2020-03-12</td>\n",
       "      <td>13.74</td>\n",
       "      <td>13.77</td>\n",
       "      <td>13.93</td>\n",
       "      <td>13.62</td>\n",
       "      <td>986497</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45</th>\n",
       "      <td>2020-03-13</td>\n",
       "      <td>12.99</td>\n",
       "      <td>13.61</td>\n",
       "      <td>13.67</td>\n",
       "      <td>12.99</td>\n",
       "      <td>1169766</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          date   open  close   high    low   volume\n",
       "0   2020-01-02  15.74  15.96  16.04  15.64  1530232\n",
       "1   2020-01-03  16.03  16.27  16.40  16.01  1116195\n",
       "2   2020-01-06  16.10  16.16  16.43  16.00   862084\n",
       "3   2020-01-07  16.22  16.24  16.37  16.04   728608\n",
       "4   2020-01-08  16.09  15.75  16.14  15.72   847824\n",
       "5   2020-01-09  15.90  15.88  16.02  15.62  1031637\n",
       "6   2020-01-10  15.88  15.78  15.90  15.61   585548\n",
       "7   2020-01-13  15.84  16.08  16.12  15.70   872133\n",
       "8   2020-01-14  16.08  15.85  16.36  15.85  1304494\n",
       "9   2020-01-15  15.88  15.61  15.95  15.54   859439\n",
       "10  2020-01-16  15.61  15.42  15.66  15.29  1028105\n",
       "11  2020-01-17  15.47  15.48  15.64  15.44   605437\n",
       "12  2020-01-20  15.52  15.54  15.70  15.44   746075\n",
       "13  2020-01-21  15.43  15.09  15.43  15.02   896603\n",
       "14  2020-01-22  15.01  15.18  15.25  14.80   719465\n",
       "15  2020-01-23  15.01  14.63  15.01  14.48  1100592\n",
       "16  2020-02-03  13.08  13.08  13.79  13.08  2259195\n",
       "17  2020-02-04  13.14  13.69  13.75  13.11  1706172\n",
       "18  2020-02-05  13.68  13.72  13.98  13.41  1491380\n",
       "19  2020-02-06  13.90  13.86  13.96  13.60  1185816\n",
       "20  2020-02-07  13.69  13.71  13.78  13.50   924853\n",
       "21  2020-02-10  13.60  13.59  13.62  13.39  1339495\n",
       "22  2020-02-11  13.69  13.88  14.03  13.65  1407507\n",
       "23  2020-02-12  13.88  13.86  13.91  13.69  1070503\n",
       "24  2020-02-13  13.80  13.74  13.97  13.70  1013205\n",
       "25  2020-02-14  13.84  14.12  14.23  13.79  1512435\n",
       "26  2020-02-17  14.13  14.46  14.46  14.02  1543696\n",
       "27  2020-02-18  14.42  14.29  14.42  14.10   973612\n",
       "28  2020-02-19  14.19  14.33  14.46  14.17   874107\n",
       "29  2020-02-20  14.36  14.68  14.71  14.19  1235444\n",
       "30  2020-02-21  14.58  14.67  14.81  14.54   995071\n",
       "31  2020-02-24  14.55  14.32  14.55  14.24  1191795\n",
       "32  2020-02-25  14.09  14.13  14.22  13.87  1144575\n",
       "33  2020-02-26  13.86  14.08  14.36  13.79  1176599\n",
       "34  2020-02-27  14.05  14.20  14.24  13.98   975271\n",
       "35  2020-02-28  13.94  13.59  14.13  13.55  1300644\n",
       "36  2020-03-02  13.64  13.88  14.04  13.55  1116581\n",
       "37  2020-03-03  14.05  13.81  14.08  13.72  1153584\n",
       "38  2020-03-04  13.77  13.78  13.87  13.60   862595\n",
       "39  2020-03-05  13.89  14.48  14.73  13.82  2686602\n",
       "40  2020-03-06  14.27  14.12  14.36  14.11  1228531\n",
       "41  2020-03-09  13.80  13.54  13.82  13.51  1665794\n",
       "42  2020-03-10  13.47  13.85  13.94  13.47  1167865\n",
       "43  2020-03-11  13.86  13.78  13.97  13.71   814382\n",
       "44  2020-03-12  13.74  13.77  13.93  13.62   986497\n",
       "45  2020-03-13  12.99  13.61  13.67  12.99  1169766"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "600600 数据\n",
      "                  date   open  close   high    low   volume\n",
      "date                                                       \n",
      "2020-01-02  2020-01-02  15.74  15.96  16.04  15.64  1530232\n",
      "2020-01-03  2020-01-03  16.03  16.27  16.40  16.01  1116195\n",
      "2020-01-06  2020-01-06  16.10  16.16  16.43  16.00   862084\n",
      "2020-01-07  2020-01-07  16.22  16.24  16.37  16.04   728608\n",
      "2020-01-08  2020-01-08  16.09  15.75  16.14  15.72   847824\n"
     ]
    }
   ],
   "source": [
    "df.index = pd.to_datetime(df.date)\n",
    "# df['openinterest'] = 0\n",
    "# df = df[columns_to_keep].copy()\n",
    "print(stock_code,'数据')\n",
    "print(df.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 策略构建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Step2.构建策略\n",
    "class Strategy_MACD(bt.Strategy):\n",
    "    \n",
    "    #设置全局策略参数\n",
    "    params = (\n",
    "        (\"short_period\", 12),\n",
    "        (\"long_period\", 26),\n",
    "        (\"signal_period\", 9),\n",
    "    )\n",
    "    \n",
    "    #日志函数\n",
    "    def log(self, txt, dt=None):\n",
    "        dt = dt or self.datas[0].datetime.date(0)\n",
    "        print('date:%s, %s' % (dt.isoformat(), txt))\n",
    "    \n",
    "    def __init__(self):\n",
    "        \n",
    "        # 初始化交易指令、买卖价格和手续费\n",
    "        self.order = None\n",
    "        self.buyprice = None\n",
    "        self.buycomm = None\n",
    "        \n",
    "        #添加MACD指标\n",
    "        self.macd = bt.indicators.MACD(\n",
    "            self.data.close,\n",
    "            period_me1=self.params.short_period,\n",
    "            period_me2=self.params.long_period,\n",
    "            period_signal=self.params.signal_period,\n",
    "        )\n",
    "    \n",
    "    # 处理和打印订单信息    \n",
    "    def notify_order(self, order):\n",
    "        \n",
    "        # 买卖订单已提交/已接受 - 无需操作\n",
    "        if order.status in [order.Submitted, order.Accepted]:\n",
    "            return\n",
    "        \n",
    "        # 检查订单是否已完成\n",
    "        if order.status in [order.Completed]:\n",
    "            if order.isbuy():\n",
    "                self.log('买入已执行，%.2f' % order.executed.price) # 记录日志\n",
    "            elif order.issell():\n",
    "                self.log('卖出已执行，%.2f' % order.executed.price)\n",
    "                \n",
    "            self.bar_executed = len(self)\n",
    "            \n",
    "        elif order.status in [order.Canceled, order.Margin, order.Rejected]:\n",
    "            self.log('订单已取消/保证金不足/拒绝')\n",
    "            \n",
    "        # 记录：没有待处理订单\n",
    "        self.order = None\n",
    "    \n",
    "    # 处理和打印交易信息    \n",
    "    def notify_trade(self, trade):\n",
    "        if not trade.isclosed:\n",
    "            return\n",
    "\n",
    "        self.log(f'本次交易毛利润：{trade.pnl:.2f},扣除交易费用后的净利润：{trade.pnlcomm:.2f}')\n",
    "\n",
    "        if trade.pnlcomm > 0:  # 如果净收益大于0，就认为这次交易盈利，否则认为这次交易亏损（同时输出交易编号）\n",
    "            self.log(f'交易获利： {trade.ref}')\n",
    "        else:\n",
    "            self.log(f'交易亏损： {trade.ref}')  \n",
    "    \n",
    "    #主要的循环策略执行部分\n",
    "    def next(self):\n",
    "        \n",
    "        # 当前资产总价\n",
    "        total_value = self.broker.getvalue()\n",
    "        \n",
    "        # 检查是否有待处理订单，如果有就不执行此轮操作\n",
    "        if self.order:\n",
    "            return\n",
    "        \n",
    "        # 回测最后一天停止交易\n",
    "        if self.datas[0].datetime.date(0) == end_date:\n",
    "            return \n",
    "        \n",
    "        # 买入卖出策略\n",
    "        \n",
    "        #检查当前仓位position\n",
    "        if not self.position:\n",
    "            # 如果仓位为0，可以进行BUY买入操作\n",
    "            if self.macd.macd[0] > self.macd.signal[0]:     # 检查是否满足买入条件\n",
    "                self.log(\"总资产价格：%.2f元\" % total_value)\n",
    "                print(\"{:-^50s}\".format(\"Split Line\"))\n",
    "                self.log('买入创建，%.2f' % self.data.close[0])\n",
    "                self.order = self.buy()\n",
    "                \n",
    "        else:\n",
    "            # 如果该股票仓位>0 ，可以进行SELL卖出操作\n",
    "            if self.macd.macd[0] < self.macd.signal[0]:   # 检查是否满足卖出条件\n",
    "                self.log(\"总资产价格：%.2f元\" % total_value) \n",
    "                print(\"{:-^50s}\".format(\"Split Line\"))\n",
    "                self.log('卖出创建，%.2f' % self.data.close[0])\n",
    "                self.order = self.sell()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 策略设置及执行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Step3.策略设置及执行\n",
    "\n",
    "def run_backtest(strategy, data, startcash, start, end):\n",
    "    # 执行回测\n",
    "    \n",
    "    # 实例化Cerebro回测引擎\n",
    "    cerebro = bt.Cerebro()\n",
    "    # 添加数据\n",
    "    datafeed1 = bt.feeds.PandasData(dataname=df,fromdate=start_date,todate=end_date)\n",
    "    datafeed2 = bt.feeds.PandasData(dataname=hs300,fromdate=start_date,todate=end_date)\n",
    "    cerebro.adddata(datafeed1, name=stock_code)\n",
    "    cerebro.adddata(datafeed2,name='sh000300')\n",
    "    # 添加策略\n",
    "    cerebro.addstrategy(Strategy_MACD)\n",
    "    # 设置初始投资总额\n",
    "    cerebro.broker.setcash(startcash)\n",
    "    # 设置交易佣金（双边万三）\n",
    "    cerebro.broker.setcommission(commission=0.0003)\n",
    "    # 设置滑点（双边万一）\n",
    "    cerebro.broker = bt.brokers.BackBroker(slip_perc=0.0001)\n",
    "    # 设置每笔交易的股票数量100\n",
    "    cerebro.addsizer(bt.sizers.FixedSize, stake=100)\n",
    "    # 添加策略分析指标\n",
    "    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='tradeanalyzer')\n",
    "    cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='annualReturn')    # 年度回报\n",
    "    cerebro.addanalyzer(bt.analyzers.Returns, _name='_Returns', tann=252)  # 年化收益\n",
    "    cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')          # 回撤\n",
    "    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')        # 夏普率\n",
    "    cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')          # 收益\n",
    "    cerebro.addanalyzer(bt.analyzers.TimeReturn,_name='_TimeReturn')\n",
    "    #cerebro.addanalyzer(bt.analyzers.TimeReturn, data=datafeed2, _name='benchmark_returns')\n",
    "    # 添加观测器\n",
    "    cerebro.addobserver(bt.observers.DrawDown)\n",
    "    cerebro.addobserver(bt.observers.Benchmark, data=datafeed2)\n",
    "    #cerebro.addobserver(bt.observers.TimeReturn, data=datafeed1)\n",
    "    \n",
    "    # 运行回测\n",
    "    results = cerebro.run()\n",
    "    \n",
    "    #计算胜率\n",
    "    total_trades = results[0].analyzers.tradeanalyzer.get_analysis()['total']['total']\n",
    "    won_trades = results[0].analyzers.tradeanalyzer.get_analysis()['won']['total']\n",
    "    win_rate = (won_trades / total_trades) * 100 if total_trades > 0 else 0\n",
    "\n",
    "    # 打印分析器输出结果\n",
    "    print(f\"初始资金: {startcash}\\n回测期间:{start_date.strftime('%Y-%m-%d')}:{end_date.strftime('%Y-%m-%d')}\")\n",
    "    print('年度汇报:', results[0].analyzers.annualReturn.get_analysis())\n",
    "    print('年化收益%:', results[0].analyzers._Returns.get_analysis()['rnorm100'])\n",
    "    print('最大回撤比例%:', results[0].analyzers.drawdown.get_analysis().max.drawdown)\n",
    "    print('夏普比率:', results[0].analyzers.sharpe.get_analysis()['sharperatio'])\n",
    "    print('胜率%:', win_rate)\n",
    "    print('累计收益：', results[0].analyzers.returns.get_analysis()['rtot'])\n",
    "    \n",
    "    \n",
    "    \n",
    "    # 提取收益序列\n",
    "    pnl = pd.Series(results[0].analyzers._TimeReturn.get_analysis())\n",
    "    # 计算累计收益\n",
    "    cumulative = (pnl + 1).cumprod()\n",
    "    # 计算回撤序列\n",
    "    max_return = cumulative.cummax()\n",
    "    drawdown = (cumulative - max_return) / max_return\n",
    "    # 计算收益评价指标\n",
    "    import pyfolio as pf\n",
    "    # 按年统计收益指标\n",
    "    perf_stats_year = (pnl).groupby(pnl.index.to_period('y')).apply(lambda data: pf.timeseries.perf_stats(data)).unstack()\n",
    "    # 统计所有时间段的收益指标\n",
    "    perf_stats_all = pf.timeseries.perf_stats((pnl)).to_frame(name='all')\n",
    "    perf_stats = pd.concat([perf_stats_year, perf_stats_all.T], axis=0)\n",
    "    perf_stats_ = round(perf_stats,4).reset_index()\n",
    "    \n",
    "    \n",
    "    # 绘制图形\n",
    "    import matplotlib.pyplot as plt\n",
    "    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号\n",
    "    import matplotlib.ticker as ticker # 导入设置坐标轴的模块\n",
    "    plt.style.use('seaborn') # plt.style.use('dark_background')\n",
    "    \n",
    "    fig, (ax0, ax1) = plt.subplots(2,1, gridspec_kw = {'height_ratios':[1.5, 4]}, figsize=(20,8))\n",
    "    cols_names = ['date', 'Annual\\nreturn', 'Cumulative\\nreturns', 'Annual\\nvolatility',\n",
    "    'Sharpe\\nratio', 'Calmar\\nratio', 'Stability', 'Max\\ndrawdown',\n",
    "    'Omega\\nratio', 'Sortino\\nratio', 'Skew', 'Kurtosis', 'Tail\\nratio',\n",
    "    'Daily value\\nat risk']\n",
    "    \n",
    "    # 绘制表格\n",
    "    ax0.set_axis_off() # 除去坐标轴\n",
    "    table = ax0.table(cellText = perf_stats_.values, \n",
    "    bbox=(0,0,1,1), # 设置表格位置， (x0, y0, width, height)\n",
    "    rowLoc = 'right', # 行标题居中\n",
    "    cellLoc='right' ,\n",
    "    colLabels = cols_names, # 设置列标题\n",
    "    colLoc = 'right', # 列标题居中\n",
    "    edges = 'open' # 不显示表格边框\n",
    "    )\n",
    "    table.set_fontsize(13)\n",
    "    \n",
    "    # 绘制累计收益曲线\n",
    "    ax2 = ax1.twinx()\n",
    "    ax1.yaxis.set_ticks_position('right') # 将回撤曲线的 y 轴移至右侧\n",
    "    ax2.yaxis.set_ticks_position('left') # 将累计收益曲线的 y 轴移至左侧\n",
    "    # 绘制回撤曲线\n",
    "    drawdown.plot.area(ax=ax1, label='drawdown (right)', rot=0, alpha=0.3, fontsize=13, grid=False)\n",
    "    # 绘制累计收益曲线\n",
    "    (cumulative).plot(ax=ax2, color='#F1C40F' , lw=3.0, label='cumret (left)', rot=0, fontsize=13, grid=False)\n",
    "    # 不然 x 轴留有空白\n",
    "    ax2.set_xbound(lower=cumulative.index.min(), upper=cumulative.index.max())\n",
    "    # 主轴定位器：每 5 个月显示一个日期：根据具体天数来做排版\n",
    "    ax2.xaxis.set_major_locator(ticker.MultipleLocator(100)) \n",
    "    # 同时绘制双轴的图例\n",
    "    h1,l1 = ax1.get_legend_handles_labels()\n",
    "    h2,l2 = ax2.get_legend_handles_labels()\n",
    "    plt.legend(h1+h2,l1+l2, fontsize=12, loc='upper left', ncol=1)\n",
    "    \n",
    "    fig.tight_layout() # 规整排版\n",
    "    plt.show()\n",
    "    \n",
    "    \n",
    "    \n",
    "    return cerebro, results\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 交易分析与评价"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Step4.交易分析与评价\n",
    "\n",
    "def evaluate_results(cerebro, results):\n",
    "    # 交易分析与评价\n",
    "    \n",
    "    #获取回测结束后的总资金\n",
    "    portvalue = cerebro.broker.getvalue()\n",
    "    #打印结果\n",
    "    print(f'最终资金: {round(portvalue,2)}')\n",
    "    \n",
    "def plot_results(cerebro):\n",
    "    # 交易过程可视化\n",
    "    \n",
    "    b = Bokeh(style='bar', plot_mode='single',show=True,scheme=Tradimo())\n",
    "    cerebro.plot(b)\n",
    "    #cerebro.plot(style='line')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pyfolio as pf"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 主函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'int' object is not subscriptable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[64], line 3\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;18m__name__\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m__main__\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m      2\u001b[0m     startcash \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100000.0\u001b[39m\n\u001b[1;32m----> 3\u001b[0m     cerebro, results \u001b[38;5;241m=\u001b[39m \u001b[43mrun_backtest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mStrategy_MACD\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstartcash\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstart_date\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mend_date\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m      4\u001b[0m     evaluate_results(cerebro, results)\n\u001b[0;32m      5\u001b[0m     plot_results(cerebro)\n",
      "Cell \u001b[1;32mIn[61], line 38\u001b[0m, in \u001b[0;36mrun_backtest\u001b[1;34m(strategy, data, startcash, start, end)\u001b[0m\n\u001b[0;32m     34\u001b[0m cerebro\u001b[38;5;241m.\u001b[39maddobserver(bt\u001b[38;5;241m.\u001b[39mobservers\u001b[38;5;241m.\u001b[39mBenchmark, data\u001b[38;5;241m=\u001b[39mdatafeed2)\n\u001b[0;32m     35\u001b[0m \u001b[38;5;66;03m#cerebro.addobserver(bt.observers.TimeReturn, data=datafeed1)\u001b[39;00m\n\u001b[0;32m     36\u001b[0m \n\u001b[0;32m     37\u001b[0m \u001b[38;5;66;03m# 运行回测\u001b[39;00m\n\u001b[1;32m---> 38\u001b[0m results \u001b[38;5;241m=\u001b[39m \u001b[43mcerebro\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     40\u001b[0m \u001b[38;5;66;03m#计算胜率\u001b[39;00m\n\u001b[0;32m     41\u001b[0m total_trades \u001b[38;5;241m=\u001b[39m results[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39manalyzers\u001b[38;5;241m.\u001b[39mtradeanalyzer\u001b[38;5;241m.\u001b[39mget_analysis()[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtotal\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtotal\u001b[39m\u001b[38;5;124m'\u001b[39m]\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\cerebro.py:1132\u001b[0m, in \u001b[0;36mCerebro.run\u001b[1;34m(self, **kwargs)\u001b[0m\n\u001b[0;32m   1128\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dooptimize \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mp\u001b[38;5;241m.\u001b[39mmaxcpus \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m   1129\u001b[0m     \u001b[38;5;66;03m# If no optimmization is wished ... or 1 core is to be used\u001b[39;00m\n\u001b[0;32m   1130\u001b[0m     \u001b[38;5;66;03m# let's skip process \"spawning\"\u001b[39;00m\n\u001b[0;32m   1131\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m iterstrat \u001b[38;5;129;01min\u001b[39;00m iterstrats:\n\u001b[1;32m-> 1132\u001b[0m         runstrat \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrunstrategies\u001b[49m\u001b[43m(\u001b[49m\u001b[43miterstrat\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   1133\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrunstrats\u001b[38;5;241m.\u001b[39mappend(runstrat)\n\u001b[0;32m   1134\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dooptimize:\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\cerebro.py:1253\u001b[0m, in \u001b[0;36mCerebro.runstrategies\u001b[1;34m(self, iterstrat, predata)\u001b[0m\n\u001b[0;32m   1251\u001b[0m         strat\u001b[38;5;241m.\u001b[39m_addobserver(\u001b[38;5;28;01mFalse\u001b[39;00m, observers\u001b[38;5;241m.\u001b[39mTrades)\n\u001b[0;32m   1252\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 1253\u001b[0m         \u001b[43mstrat\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_addobserver\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mobservers\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDataTrades\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m   1255\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m multi, obscls, obsargs, obskwargs \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mobservers:\n\u001b[0;32m   1256\u001b[0m     strat\u001b[38;5;241m.\u001b[39m_addobserver(multi, obscls, \u001b[38;5;241m*\u001b[39mobsargs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mobskwargs)\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\strategy.py:257\u001b[0m, in \u001b[0;36mStrategy._addobserver\u001b[1;34m(self, multi, obscls, *obsargs, **obskwargs)\u001b[0m\n\u001b[0;32m    255\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m multi:\n\u001b[0;32m    256\u001b[0m     newargs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mlist\u001b[39m(itertools\u001b[38;5;241m.\u001b[39mchain(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdatas, obsargs))\n\u001b[1;32m--> 257\u001b[0m     obs \u001b[38;5;241m=\u001b[39m obscls(\u001b[38;5;241m*\u001b[39mnewargs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mobskwargs)\n\u001b[0;32m    258\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstats\u001b[38;5;241m.\u001b[39mappend(obs, obsname)\n\u001b[0;32m    259\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\metabase.py:86\u001b[0m, in \u001b[0;36mMetaBase.__call__\u001b[1;34m(cls, *args, **kwargs)\u001b[0m\n\u001b[0;32m     84\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mcls\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m     85\u001b[0m     \u001b[38;5;28mcls\u001b[39m, args, kwargs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mdoprenew(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m---> 86\u001b[0m     _obj, args, kwargs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mdonew(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m     87\u001b[0m     _obj, args, kwargs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mdopreinit(_obj, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m     88\u001b[0m     _obj, args, kwargs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39mdoinit(_obj, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\observers\\trades.py:118\u001b[0m, in \u001b[0;36mMetaDataTrades.donew\u001b[1;34m(cls, *args, **kwargs)\u001b[0m\n\u001b[0;32m    115\u001b[0m     lnames \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mtuple\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdata\u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;241m.\u001b[39mformat(x) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;28mlen\u001b[39m(_obj\u001b[38;5;241m.\u001b[39mdatas)))\n\u001b[0;32m    117\u001b[0m \u001b[38;5;66;03m# Generate a new lines class\u001b[39;00m\n\u001b[1;32m--> 118\u001b[0m linescls \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mcls\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mlines\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_derive\u001b[49m\u001b[43m(\u001b[49m\u001b[43muuid\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43muuid4\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhex\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlnames\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    120\u001b[0m \u001b[38;5;66;03m# Instantiate lines\u001b[39;00m\n\u001b[0;32m    121\u001b[0m _obj\u001b[38;5;241m.\u001b[39mlines \u001b[38;5;241m=\u001b[39m linescls()\n",
      "File \u001b[1;32mc:\\ProgramData\\anaconda3\\lib\\site-packages\\backtrader\\lineseries.py:156\u001b[0m, in \u001b[0;36mLines._derive\u001b[1;34m(cls, name, lines, extralines, otherbases, linesoverride, lalias)\u001b[0m\n\u001b[0;32m    153\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m line, linealias \u001b[38;5;129;01min\u001b[39;00m l2add:\n\u001b[0;32m    154\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(linealias, string_types):\n\u001b[0;32m    155\u001b[0m         \u001b[38;5;66;03m# a tuple or list was passed, 1st is name\u001b[39;00m\n\u001b[1;32m--> 156\u001b[0m         linealias \u001b[38;5;241m=\u001b[39m \u001b[43mlinealias\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[0;32m    158\u001b[0m     desc \u001b[38;5;241m=\u001b[39m LineAlias(line)  \u001b[38;5;66;03m# keep a reference below\u001b[39;00m\n\u001b[0;32m    159\u001b[0m     \u001b[38;5;28msetattr\u001b[39m(newcls, linealias, desc)\n",
      "\u001b[1;31mTypeError\u001b[0m: 'int' object is not subscriptable"
     ]
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "    startcash = 100000.0\n",
    "    cerebro, results = run_backtest(Strategy_MACD, df, startcash, start_date, end_date)\n",
    "    evaluate_results(cerebro, results)\n",
    "    plot_results(cerebro)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
